import { createStore, Commit } from 'vuex'
import { get, post, axiosInstance } from './axiosDefaults'
import axios, { AxiosRequestConfig } from 'axios'
import { flattenArr, objToArr } from './flatten'

// 上传文件错误后端返回的数据类型
export interface imageData {
  _id?: string;
  url?: string;
  createdAt?: string;
}
// uploader组件请求类型
export interface loaderResType<p> {
  code: number;
  msg: string;
  data: p
}
// columns和posts 数据的扁平化对象形式类型
// { id: {posts} }  { id: { column } }
interface ArrDataToObj<P> {
  [id: string]: P
}
// 异步get请求 commit
const getAndCommit = async (url: string, mutationsName: string, commit: Commit) => {
  const result: any = await get(url)
  commit(mutationsName, result.data.data)
  return result.data.data
}
// 异步post请求 commit    postData --> {email, password}
const postAndCommit = async (url: string, mutationsName: string, commit: Commit, postData: any) => {
  const result: any = await post(url, postData) // 发送post 请求
  commit(mutationsName, result.data.data) // 触发mutations 方法
  return result.data.data // 把结果返回出去
}

const asyncAndCommit = async (url: string, mutationsName: string, commit: Commit, config: AxiosRequestConfig = { method: 'get' }, theArgs?: any) => {
  const { data } = await axios(url, config)
  if (theArgs) {
    commit(mutationsName, { data, theArgs })
  } else {
    commit(mutationsName, data)
  }
  return data
}
export interface ImageProps { // 请求图片数据格式类型
  _id?: string;
  url?: string;
  createdAt?: string;
  fitUrl?: string;
}
// 错误处理状态和信息类型
export interface GlobalErr {
  isErr: boolean;
  message?: string;
}
export interface avatarProps { // 图片 类型
  id: string;
  url: string;
}
export interface userProps { // 用户登录类型
  isLogin: boolean;
  nickName?: string;
  _id?: string;
  column?: string;
  email?: string;
  avatar?: ImageProps;
  description?: string;
}
export interface ColumnProps { // column 数组类型
  _id: string;
  title: string;
  avatar?: ImageProps;
  description: string;
}
export interface PostProps { // 内容列表请求类型
  _id?: string;
  title: string;
  excerpt?: string;
  content?: string;
  image?: ImageProps | string;
  createdAt?: string;
  column: string;
  author?: string | userProps;
}
interface loadedColumnsProps {
  columnId: any;
  currentPage: number;
  total: number;
}
export interface GlobalDataProps { // 全局类型
  err: GlobalErr;
  token: string;
  isLoading:boolean;
  columns: { data: ArrDataToObj<ColumnProps>, total: number, currentPage: number };
  posts: { data: ArrDataToObj<PostProps>, loadedColumns: ArrDataToObj<loadedColumnsProps>, total: number, currentPage: number };
  user: userProps;
}
export interface dataProps { // 请求数据格式类型
  _id: string;
  title: string;
  description: string;
  avatar?: ImageProps
}
const store = createStore<GlobalDataProps>({
  state: {
    err: { isErr: false },
    token: localStorage.getItem('token') || '', // 登录token
    isLoading: false, // loading
    columns: { data: {}, total: 0, currentPage: 1 },
    posts: { data: {}, loadedColumns: {}, total: 0, currentPage: 0 }, // content 列表
    user: { isLogin: false } // user
  },
  mutations: {
    // 创建content逻辑
    createPost (store, payload) {
      store.posts.data[payload._id] = payload
    },
    // 异步请求更新columns列表逻辑
    fetchColumns (state, rawData) {
      // state.columns.total = rawData.count
      // state.columns.data = { ...state.columns.data, ...flattenArr(rawData.list) }
      state.columns = {
        data: { ...state.columns.data, ...flattenArr(rawData.list) },
        total: rawData.count,
        currentPage: rawData.currentPage
      }
    },
    // 单个columns逻辑
    fetchColumnOne (state, rawData) {
      state.columns.data[rawData._id] = rawData
    },
    // 异步请求更新content列表逻辑
    fetchColumnPost (state, { data: rawData, theArgs: columnId }) {
      state.posts.data = { ...state.posts.data, ...flattenArr(rawData.data.list) }
      state.posts.total = rawData.data.count
      state.posts.currentPage = rawData.data.currentPage
      state.posts.loadedColumns[columnId] = { columnId, currentPage: rawData.data.currentPage, total: rawData.data.count }
    },
    // loading 逻辑
    fetchLoading (store, payload) {
      store.isLoading = payload
    },
    // login token
    login (store, payload) {
      store.token = payload.token
      localStorage.setItem('token', payload.token) // 存储token
      axiosInstance.defaults.headers.common.Authorization = `Bearer ${payload.token}`
    },
    uploadPost (state, { data }) {
      state.posts.data[data._id] = data
    },
    // 退出登录的操作
    logout (state) {
      state.token = ''
      localStorage.removeItem('token')
      delete axiosInstance.defaults.headers.common.Authorization
    },
    usercurrent (store, payload) {
      store.user = { isLogin: true, ...payload }
    },
    // 错误信息
    fetchErr (store, payload: GlobalErr) {
      store.err = payload
    },
    fetchDetailOne (state, { data: rawData }) {
      state.posts.data[rawData._id] = rawData
    },
    deletePost (state, { data }) {
      delete state.posts.data[data._id]
    }
  },
  actions: {
    deletePostDetail ({ commit }, id) {
      return asyncAndCommit(`/posts/${id}`, 'deletePost', commit, {
        method: 'delete',
        params: { icode: '38CD209A8A08B4B6' }
      })
    },
    updatePost ({ commit }, { id, payload }) {
      return asyncAndCommit(`/posts/${id}`, 'uploadPost', commit, {
        method: 'PATCH',
        data: payload,
        headers: { 'Content-Type': 'application/json' }
      })
    },
    getColumns (context, { currentPage, pageSize } = { currentPage: 1, pageSize: 5 }) {
      // actions columns逻辑
      const { state } = context
      if (state.columns.total > 0) {
        if ((Math.ceil(state.columns.total / pageSize) > state.columns.currentPage)) {
          return getAndCommit(`/columns?currentPage=${currentPage}&pageSize=${pageSize}`, 'fetchColumns', context.commit)
        }
      } else {
        return getAndCommit(`/columns?currentPage=${currentPage}&pageSize=${pageSize}`, 'fetchColumns', context.commit)
      }
    },
    getColumnsOne (context, cid) {
      // actions 单个column 逻辑
      if (!context.state.columns.data[cid]) {
        return getAndCommit(`/columns/${cid}`, 'fetchColumnOne', context.commit)
      }
    },
    getColumnsPost (context, { id, currentPage: pageCurrent, pageSize }) {
      let totalCurrentPage = null
      if (context.state.posts.loadedColumns.total) {
        const { total, currentPage } = context.state.posts.loadedColumns[id]
        let newCurrentPage = currentPage
        totalCurrentPage = Math.ceil(total / pageSize)
        if (totalCurrentPage === 0 || totalCurrentPage > newCurrentPage++) {
          return asyncAndCommit(`/columns/${id}/posts?currentPage=${pageCurrent}&pageSize=${pageSize}`, 'fetchColumnPost', context.commit, { method: 'get' }, id)
        }
      } else {
        return asyncAndCommit(`/columns/${id}/posts?currentPage=${pageCurrent}&pageSize=${pageSize}`, 'fetchColumnPost', context.commit, { method: 'get' }, id)
      }
    },
    postLogin (context, postData) {
      // 把async函数返回给 dispatch方法
      return postAndCommit('/user/login', 'login', context.commit, postData)
    },
    createPost (context, postData) {
      // 把async函数返回给 dispatch方法
      return postAndCommit('/posts', 'createPost', context.commit, postData)
    },
    usercurrent (context) { // 发送token 请求头。 获取参数
      return getAndCommit('/user/current', 'usercurrent', context.commit)
    },
    // 在actions 里 可以再自定义一个actions
    tokenCurrent ({ dispatch }, userData) { // action
      // 可以派发两个 actions 方法。使用then方法先后触发
      // 由login 在请求头重发送token 令牌，令牌通过验证，触发
      // 获取当前用户登录信息的请求。
      return dispatch('postLogin', userData).then(() => {
        return dispatch('usercurrent')
      })
    },
    postDetailRst (context, id) {
      if (!context.state.posts.data[id] || !context.state.posts.data[id].content) {
        return asyncAndCommit(`/posts/${id}`, 'fetchDetailOne', context.commit)
      } else {
        return Promise.resolve(context.state.posts.data[id])
      }
    }
  },
  getters: { // vuex 中的计算属性，会返回一个计算值，全局使用
    getColumnById: (state) => (id: string) => {
      return state.columns.data[id]
    },
    getPostsByCid: (state) => (cid: string) => {
      return objToArr(state.posts.data).filter(post => {
        return post.column === cid
      })
    },
    getPostsDetailById: (state) => (cid: string) => {
      return state.posts.data[cid]
    },
    getColumnList: (state) => {
      return objToArr(state.columns.data)
    }
  }
})

export default store
